package org.simpleframework.inject.annotation;

import lombok.extern.slf4j.Slf4j;
import org.simpleframework.core.BeanContainer;
import org.simpleframework.util.ClassUtil;
import org.simpleframework.util.ValidationUtil;

import java.lang.reflect.Field;
import java.util.Set;

/**
 * @program: simpleframework
 * @description:
 * @author: lishuang
 * @create: 2021-11-24 10:30
 **/
@Slf4j
public class DependencyInjector {

    private BeanContainer beanContainer;

    public  DependencyInjector(){
        beanContainer = BeanContainer.getInstance();
    }

    /**
     * 执行Ioc
     */
    public void  doIoc(){
        //1.遍历Bean容器中所有的Class对象
        Set<Class<?>> classSet = beanContainer.getClasses();
        if (ValidationUtil.isEmpty(classSet)){
            log.warn("BeanContainer is empty");
            return;
        }
        //2.遍历Class对象的所有成员变量
        for (Class<?> clazz : classSet) {
            Field[] declaredFields = clazz.getDeclaredFields();
            if (ValidationUtil.isEmpty(declaredFields)){
                continue;
            }
            for (Field field : declaredFields) {
                //3.找出被Autowired标记的成员变量
                if (field.isAnnotationPresent(Autowired.class)){
                    Autowired autowired = field.getAnnotation(Autowired.class);
                    String autowiredValue = autowired.value();
                    //4.获取这些成员变量的类型
                    Class<?> fieldClass = field.getType();
                    //5.获取这些成员变量的类型在容器里对应的实例
                    Object fieldValue = getFieldInstance(fieldClass, autowiredValue);
                    if(fieldValue == null){
                        throw new RuntimeException("unable to inject relevant type，target fieldClass is:" + fieldClass.getName() + " autowiredValue is : " + autowiredValue);
                    }
                    //6.通过反射将对应的成员变量实例注入到成员变量所在类的实例里
                    Object targetBean = beanContainer.getBean(clazz);
                    ClassUtil.setField(field,targetBean,fieldValue,true);
                }
            }
        }

    }

    /**
     * 根据据Class在beanContainer里获取其实例或者实现类
     * @param fieldClass
     * @param autowiredValue
     * @return
     */
    private Object getFieldInstance(Class<?> fieldClass, String autowiredValue) {
        Object fieldValue = beanContainer.getBean(fieldClass);
        if(fieldValue!=null){
            return fieldValue;
        }else {
            //说明这个成员变量是一个接口，需要得到它的实现类实例注入到bean容器
           Class<?> implementedClass=  getImplement(fieldClass,  autowiredValue);
            if(implementedClass != null){
                return beanContainer.getBean(implementedClass);
            } else {
                return null;
            }
        }
    }

    /**
     * 获取接口的实现类
     * @param fieldClass
     * @param autowiredValue
     * @return
     */
    private Class<?> getImplement(Class<?> fieldClass, String autowiredValue) {
        Set<Class<?>> classSet =  beanContainer.getClassesBySuper(fieldClass);
        if(!ValidationUtil.isEmpty(classSet)){
            if(ValidationUtil.isEmpty(autowiredValue)){
                if(classSet.size() == 1){
                    return classSet.iterator().next();
                } else {
                    //如果多于两个实现类且用户未指定其中一个实现类，则抛出异常
                    throw new RuntimeException("multiple implemented classes for " + fieldClass.getName() + " please set @Autowired's value to pick one");
                }
            } else {
                for(Class<?> clazz : classSet){
                    if(autowiredValue.equals(clazz.getSimpleName())){
                        return clazz;
                    }
                }
            }
        }
        return null;
    }
}
